#ifndef CODE_METHOD_H
#define CODE_METHOD_H
#include "Method.h"
#include <vector>

#define EXPRESSION_MESSAGE 0
#define EXPRESSION_VAR 1
#define EXPRESSION_CLOSURE 2
#define EXPRESSION_SELF 3
#define EXPRESSION_CONST 4


class MessageSend;
class InterpretPrescription;
class Expression{
   public:
   int type;
   union{
      MessageSend* message;
      Object* constant;
      InterpretPrescription* cp;
   };
   string var;
};
class MessageSend{
   public:
   Expression* object;
   string selector;
   vector<Expression*> arguments;
};
#define STATEMENT_ASSIGN 0
#define STATEMENT_RETURN 1
#define STATEMENT_DISCARD 2
class Statement{
   public:
   int type;
   string lvalue;
   Expression* rvalue;
};
Statement ast_assign(string lvalue,Expression* expr);
Statement ast_return(Expression* expr);
Statement ast_discard(Expression* expr);
Expression* ast_message(Expression* object,string selector,int count,...);
Expression* ast_var(string var);
Expression* ast_self();
Expression* ast_const(Object* o);
Expression* ast_closure(InterpretPrescription* cp);
void print_stmt(Image*,Statement stmt);
void print_expr(Image*,Expression* expr);

class CodeMethod:public Method{
   public:
      CodeMethod(Image* image,string selector,Class* cls=NULL);
      void addTemp(string name,Type* type);
      void add(Statement codeBlock);
      virtual Object* execute(Image* i,Object* receiver,int argc,Object** argv);
      void addArgument(Type* type,string name);
   private:
      list<Statement> code;
      map<string,Type*> temps;
      vector<string> argumentsNames;
};
Object* execute_expr(Expression* e,Image* i,Object* self,map<string,Object*>* temps);
Object* execute_stmt(Statement st,Image* i,Object* self,map<string,Object*>* temps);
void print_stmt(Statement stmt);
void print_expr(Expression* expr);

#endif
